package fr.sedoo.rbv.metadataws;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;

import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.lang.StringUtils;

import fr.sedoo.commons.metadata.utils.domain.MetadataTools;
import fr.sedoo.commons.metadata.utils.domain.SedooMetadata;
import fr.sedoo.commons.metadata.utils.domain.Summary;
import fr.sedoo.commons.metadata.utils.pdf.PrintService;
import fr.sedoo.commons.spring.SpringBeanFactory;
import fr.sedoo.commons.web.dao.WebConfigVersionDAO;
import fr.sedoo.rbv.geonetwork.config.GeonetworkConfig;
import fr.sedoo.rbv.geonetwork.domain.GeonetworkUser;
import fr.sedoo.rbv.geonetwork.request.MetadataAddOrUpdateWithIdRequest;
import fr.sedoo.rbv.geonetwork.request.MetadataAddWithoutIdRequest;
import fr.sedoo.rbv.geonetwork.request.MetadataByIdRequest;
import fr.sedoo.rbv.geonetwork.request.MetadataExistRequest;
import fr.sedoo.rbv.geonetwork.request.SearchCriteria;
import fr.sedoo.rbv.geonetwork.request.SearchRequest;

@Path("/integration")
public class IntegrationService {

	static SpringBeanFactory factory;
	static GeonetworkConfig config;

	public final static String RBV_FORMAT_NAME = "RBV"; 
	private final static String ISO19139_FORMAT_NAME = "ISO19139";

	@GET
	@Path("/version")
	public Response getVersion() 
	{
		WebConfigVersionDAO dao = new WebConfigVersionDAO();
		String version = dao.getVersion();
		return Response.status(200).entity(version).build();
	}


	@GET
	@Path("/exist/{uuid}")
	public Response exist(@PathParam("uuid") String uuid) 
	{
		if (StringUtils.isEmpty(uuid))
		{
			return Response.status(HttpStatus.SC_OK).entity(Boolean.FALSE.toString()).build();
		}
		else
		{
			MetadataExistRequest request = new MetadataExistRequest(uuid);
			Boolean result;
			try {
				result = request.execute();
				return Response.status(HttpStatus.SC_OK).entity(result.toString()).build();
			} catch (Exception e) {
				return Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
			}

		}
	}

	@GET
	@Path("/getObservatoryUuid")
	public Response getObservatoryUuid(@QueryParam("observatoryName") String observatoryName) 
	{
		if (StringUtils.isEmpty(observatoryName))
		{
			return Response.status(HttpStatus.SC_BAD_REQUEST).build();
		}
		else
		{
			try
			{
				String uuid = getObservatoryUuidByName(observatoryName);
				if (uuid == null)
				{
					return Response.status(HttpStatus.SC_BAD_REQUEST).build();
				}
				else
				{
					return Response.status(HttpStatus.SC_OK).entity(uuid.toString()).build();
				}
			}
			catch (Exception e) {
				return Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
			}

		}
	}

	@GET
	@Path("/getExpertimentalSiteUuid")
	public Response getExpertimentalSiteUuid(@QueryParam("observatoryName") String observatoryName, @QueryParam("experimentalSiteName") String experimentalSiteName) 
	{
		if (StringUtils.isEmpty(experimentalSiteName))
		{
			return Response.status(HttpStatus.SC_BAD_REQUEST).build();
		}
		if (StringUtils.isEmpty(observatoryName))
		{
			return Response.status(HttpStatus.SC_BAD_REQUEST).build();
		}
		else
		{
			try
			{
				String parentUuid = getObservatoryUuidByName(observatoryName);

				SearchCriteria criteria = new SearchCriteria();
				criteria.setParentUuid(parentUuid);
				SearchRequest request = new SearchRequest();
				request.setDisplayLanguages(new ArrayList<String>());
				request.setCriteria(criteria);
				request.setPagePosition(1);
				request.setPageSize(1000);

				boolean isCorrectlyExecuted = false;
				try {
					isCorrectlyExecuted = request.fetchSummaries();
				} catch (Exception e) {
					throw new Exception("Uncorrect execution");
				}
				if (isCorrectlyExecuted == false)
				{
					throw new Exception("Uncorrect execution");
				}
				else
				{
					List<Summary> summaries = request.getSummaries();
					String uuid = null;
					for (Summary summary : summaries) {
						String currentName = RBVMetadata.getExperimentalSiteNameFromSummary(summary);
						if (currentName.compareToIgnoreCase(experimentalSiteName)==0)
						{
							uuid = summary.getUuid();
							break;
						}
					}
					if (uuid == null)
					{
						return Response.status(HttpStatus.SC_BAD_REQUEST).build();
					}
					else
					{
						return Response.status(HttpStatus.SC_OK).entity(uuid.toString()).build();
					}
				}


			}
			catch (Exception e) {
				return Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
			}

		}
	}

	private String getObservatoryUuidByName(String observatoryName) throws Exception
	{
		SearchCriteria criteria = new SearchCriteria();
		criteria.setIncludesObservatories(true);
		SearchRequest request = new SearchRequest();
		request.setDisplayLanguages(new ArrayList<String>());
		request.setCriteria(criteria);
		//On force le retour de tous les observatoire
		request.setPagePosition(1);
		request.setPageSize(1000);

		boolean isCorrectlyExecuted = false;
		try {
			isCorrectlyExecuted = request.fetchSummaries();
		} catch (Exception e) {
			throw new Exception("Uncorrect execution");
		}
		if (isCorrectlyExecuted == false)
		{
			throw new Exception("Uncorrect execution");
		}
		else
		{
			List<Summary> summaries = request.getSummaries();
			String uuid = null;
			for (Summary summary : summaries) {
				String currentName = RBVMetadata.getObservatoryNameFromSummary(summary);
				if (currentName.compareToIgnoreCase(observatoryName)==0)
				{
					return summary.getUuid();
				}
			}
			return null;
		}
	}

	@GET
	@Path("/getById/{uuid}")
	@Produces("application/xml")
	public Response getById(@PathParam("uuid") String uuid) 
	{
		if (StringUtils.isEmpty(uuid))
		{
			return Response.status(400).build();
		}
		else
		{
			MetadataByIdRequest request = new MetadataByIdRequest(uuid);
			try
			{
				boolean execute = request.execute();
				if (execute)
				{
					String result = request.getRawXML();
					return Response.status(200).entity(result).build();
				}
				else
				{
					return Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).entity("An error has happened. The action hasn't been performed.").build();
				}
			}
			catch (Exception e)
			{
				return Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).entity("An error has happened:"+e.getMessage()+". The action hasn't been performed.").build();	
			}
		}
	}

	@GET
	@Path("/getPdfById/{localeCode}/{uuid}")
	@Produces("application/pdf")
	public Response getPdfById(@PathParam("localeCode") String localeCode, @PathParam("uuid") String uuid) 
	{
		if (StringUtils.isEmpty(uuid))
		{
			return Response.status(400).build();
		}
		else
		{
			Locale currentLocale = new Locale(localeCode);

			SpringBeanFactory beanFactory = new SpringBeanFactory();
			ArrayList<Locale> locales = new ArrayList<Locale>();
			ArrayList<String> tmp = (ArrayList<String>) beanFactory.getBeanByName("metadataLanguages");
			Iterator<String> iterator = tmp.iterator();
			while (iterator.hasNext()) {
				locales.add(new Locale(iterator.next()));
			}
			MetadataByIdRequest request = new MetadataByIdRequest(uuid);
			File output = null;
			try
			{
				boolean execute = request.execute();
				if (execute)
				{
					String content = request.getRawXML();
					SedooMetadata metadata = MetadataTools.fromISO19139(content);
					output = File.createTempFile("rbvPdfOutput", ".pdf");
					PrintService printService = new PrintService(currentLocale, locales);
					printService.setOutputFileName(output.getPath());
					printService.metadataToPdf(metadata);
					ResponseBuilder response = Response.ok((Object) output);
					response.header("Content-Disposition", "attachment; filename=\""+uuid+".pdf\"");
					return response.status(200).build();
				}
				else
				{
					return Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).entity("An error has happened. The action hasn't been performed.").build();
				}
			}
			catch (Exception e)
			{
				return Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).entity("An error has happened:"+e.getMessage()+". The action hasn't been performed.").build();	
			}
			finally
			{
				if (output != null)
				{
					if (output.exists())
					{
						output.deleteOnExit();
					}
				}
			}
		}
	}


	@POST
	@Path("/addOrUpdateWithId")
	@Consumes("application/x-www-form-urlencoded")
	public Response addOrUpdateWithId(@FormParam("src") String src, @FormParam("format") String format, @FormParam("login") String login, @FormParam("password") String password) 
	{
		Response aux = checkAddRequest(src, format, login, password);
		if (aux != null)
		{
			return aux;
		}

		else
		{
			try
			{
				SedooMetadata metadata = RBVTools.fromRBV(src);
				String iso191339Content = MetadataTools.toISO19139(metadata); 
				GeonetworkUser user = new GeonetworkUser(login, password);
				MetadataAddOrUpdateWithIdRequest request = new MetadataAddOrUpdateWithIdRequest(iso191339Content, user);
				boolean execute = request.execute();
				if (execute)
				{
					return Response.status(HttpStatus.SC_OK).build();
				}
				else
				{
					return Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).entity("An error has happened. The action hasn't been performed.").build();
				}
			}
			catch (Exception e)
			{
				return Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).entity("An error has happened:"+e.getMessage()+". The action hasn't been performed.").build();
			}
		}
	}

	@POST
	@Path("/addWithoutId")
	@Consumes("application/x-www-form-urlencoded")
	public Response addWithoutId(@FormParam("src") String src, @FormParam("format") String format, @FormParam("login") String login, @FormParam("password") String password) 
	{
		Response aux = checkAddRequest(src, format, login, password);
		if (aux != null)
		{
			return aux;
		}
		else
		{
			try
			{
				SedooMetadata metadata = RBVTools.fromRBV(src);
				String iso191339Content = MetadataTools.toISO19139(metadata); 
				GeonetworkUser user = new GeonetworkUser(login, password);
				MetadataAddWithoutIdRequest request = new MetadataAddWithoutIdRequest(iso191339Content, user);
				boolean execute = request.execute();
				if (execute)
				{
					String uuid = request.getUuid();
					return Response.status(HttpStatus.SC_OK).entity(uuid).build();
				}
				else
				{
					return Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).entity("An error has happened. The action hasn't been performed.").build();
				}
			}
			catch (Exception e)
			{
				return Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).entity("An error has happened:"+e.getMessage()+". The action hasn't been performed.").build();
			}
		}
	}


	private Response checkAddRequest(String src, String format, String login, String password)
	{
		if (StringUtils.isEmpty(src))
		{
			return Response.status(HttpStatus.SC_BAD_REQUEST).entity("Missing parameter:src").build();
		}
		if (StringUtils.isEmpty(format))
		{
			return Response.status(HttpStatus.SC_BAD_REQUEST).entity("Missing parameter:format").build();
		}

		if (StringUtils.isEmpty(login))
		{
			return Response.status(HttpStatus.SC_BAD_REQUEST).entity("Missing parameter:login").build();
		}
		if (StringUtils.isEmpty(password))
		{
			return Response.status(HttpStatus.SC_BAD_REQUEST).entity("Missing parameter:password").build();
		}

		if (format.trim().compareToIgnoreCase(RBV_FORMAT_NAME)!=0)
		{
			return Response.status(HttpStatus.SC_BAD_REQUEST).entity("Wrong parameter:format can only be either "+RBV_FORMAT_NAME+" or "+ISO19139_FORMAT_NAME).build();
		}
		return null;

	}


}
